using System;
using System.Collections.Generic;
using System.Text;
using XNALibrary.Interfaces;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.IO;
using Microsoft.Xna.Framework.Storage;
using XNALibrary.Game;

namespace XNALibrary.Landspace
{
    public class Landspace
    {
        private VertexPositionTexture[] grid;
        private Effect effect;
        private Texture texture;
        private int detail;

        public Landspace()
        {
            detail = 257;

            grid = this.GenerateGrid(detail, 75, new Vector3(-5, 0, -5), "Resources/LandscapeHeights.data");

            //load color Texture
            texture = BaseGame.content.Load<Texture>("Resources/Textures/Landscape");
            effect = BaseGame.content.Load<Effect>("Resources/Effects/Terrain/Terrain");

            effect.Parameters["DiffuseTexture"].SetValue(texture);
        }

        public Landspace(string pathTexture, string pathHeightData)
        {
            detail = 257;

            grid = this.GenerateGrid(detail, 75, new Vector3(-5, 0, -5), pathHeightData);

            //load color Texture
            texture = BaseGame.content.Load<Texture>(pathTexture);
            effect = BaseGame.content.Load<Effect>("Content/Effects/Terrain");

            effect.Parameters["DiffuseTexture"].SetValue(texture);
        }

        public float CalculateZ(int x, int y, byte[] heights)
        {
            float heightPercent = heights[x + y * detail] / 255.0f;
            return heightPercent * 7;
        }

        private VertexPositionTexture[] GenerateGrid(int detail, float size, Vector3 origin, string pathHeightData)
        {
            FileStream file = File.Open(Path.Combine(StorageContainer.TitleLocation, pathHeightData),
                    FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

            byte[] heights = new byte[detail * detail];
            file.Read(heights, 0, detail * detail);
            file.Close();

            VertexPositionTexture[] result;
            int nrCells = (detail - 1) * (detail - 1);
            int nrTris = nrCells * 2;
            result = new VertexPositionTexture[nrTris * 3];
            VertexPositionTexture point1, point2, point3, point4;
            int cellIndex = 0;
            float maxUV = detail - 1;

            for (int i = 0; i < detail - 1; i++)
            {
                for (int j = 0; j < detail - 2; j++)
                {
                    //6*i..6*i+2      6*i+3..6*i+5
                    /**
                    *      1----2
                    *      |\   |
                    *      | \  |
                    *      |  \ |
                    *      |   \|
                    *      4----3
                    */

                    //point
                    point1 = new VertexPositionTexture();
                    point2 = new VertexPositionTexture();
                    point3 = new VertexPositionTexture();
                    point4 = new VertexPositionTexture();

                    point1.TextureCoordinate = new Vector2(i / (maxUV), j / (maxUV));
                    point1.Position = new Vector3(size * i / (maxUV), CalculateZ(i, j, heights), size * j / (maxUV));
                    point1.Position = Vector3.Add(origin, point1.Position);

                    point2.TextureCoordinate = new Vector2(i / (maxUV), (j + 1) / (maxUV));
                    point2.Position = new Vector3(size * i / (maxUV), CalculateZ(i, j + 1, heights), size * (j + 1) / (maxUV));
                    point2.Position = Vector3.Add(origin, point2.Position);

                    point3.TextureCoordinate = new Vector2((i + 1) / (maxUV), (j + 1) / (maxUV));
                    point3.Position = new Vector3(size * (i + 1) / (maxUV), CalculateZ(i + 1, j + 1, heights), size * (j + 1) / (maxUV));
                    point3.Position = Vector3.Add(origin, point3.Position);

                    point4.TextureCoordinate = new Vector2((i + 1) / (maxUV), j / (maxUV));
                    point4.Position = new Vector3(size * (i + 1) / (maxUV), CalculateZ(i + 1, j, heights), size * j / (maxUV));
                    point4.Position = Vector3.Add(origin, point4.Position);

                    result[6 * cellIndex] = point1;
                    result[6 * cellIndex + 1] = point3;
                    result[6 * cellIndex + 2] = point4;

                    result[6 * cellIndex + 3] = point1;
                    result[6 * cellIndex + 4] = point2;
                    result[6 * cellIndex + 5] = point3;
                    cellIndex++;
                }
            }
            return result;

        }

        public void Draw()
        {
            using (VertexDeclaration decl = new VertexDeclaration(BaseGame.device, VertexPositionTexture.VertexElements))
            {
                BaseGame.device.VertexDeclaration = decl;
                BaseGame.device.RenderState.CullMode = CullMode.CullClockwiseFace;

                effect.Parameters["WorldViewProj"].SetValue(Matrix.CreateScale(500)* Matrix.CreateTranslation(new Vector3(0,0,-10000))
                    * BaseGame.camera.View * BaseGame.camera.Projection);
                int nrTriangles = grid.Length / 3;

                effect.Begin();
                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    BaseGame.device.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, grid, 0, nrTriangles);
                    pass.End();
                }
                effect.End();
                BaseGame.device.RenderState.CullMode = CullMode.CullCounterClockwiseFace;
            }
        }
    }
}
